Interactive Data Visualization (IDV) for Efficacy Analysis

A New Approach to Exploration Empowered by Custom teal Modules

Yufan Chen & Mathias Lebreton // 30th October, 2025
Shiny Day

Agenda


  • Project Background
  • Interactive Reporting App Demo
  • Custom teal Modules
  • User Feedback

Project Background




Study details:

  • 3 Cohorts

  • 25 Efficacy Endpoints

  • 13 Analysis Subgroups

  • Ongoing Data Refresh (every 2 months)

  • Long-Term Extension Planned

Time-consuming traditional approaches, limited dynamic data exploration, and the lack of real-time updates motivated us to create a shiny solution.

Project Background


App development timeline:

Interactive Reporting App Demo


Interactive Reporting App link:
https://rconnect.space.jnj.com/content/99a6511a-5b02-44f2-94bb-73e54e1aaaf0/

Custom teal modules


teal open-source framework offers many modules we can add to our app. If they don’t meet stakeholder needs, we can create a custom teal module


1- Build from static ggplot2, identify interactive elements







Custom teal modules


teal open-source framework offers many modules we can add to our app. If they don’t meet stakeholder needs, we can create a custom teal module


1- Build from static ggplot2, identify interactive elements

2- Convert ggplot2 to plotly for interactive visualization

Custom teal modules


3- Select appropriate teal.widgets item for the UI
E.g. Dropdown list -> teal.widgets::optionalSelectInput()

4- Define module parameters to easily control endpoints, variables, and more

lineplot_module(
  label_mod = "Lineplot - Mean",
  dataname = "ADOE",
  vars = choices_selected(
    choices = variable_choices(my_data[["ADOE"]], c("AVAL", "CHG")),
    selected = c("AVAL")
  ),
  parameter =  choices_selected(
    choices = value_choices(my_data[["ADOE"]],"PARAMCD","PARAM"),
    selected = "GAAREA"
  ),
  xtime =  choices_selected(
    choices = variable_choices(my_data[["ADOE"]], c("AVISIT")),
    selected = "AVISIT", fixed = TRUE
  ),
  splitby =  choices_selected(
    variable_choices(my_data[["ADSL"]], c("TRT01P")),
    selected = "TRT01P", fixed = TRUE
  ),
  subgroup = choices_selected(
    choices = variable_choices(my_data[["ADSL"]], 
                               c("SEX", "AGEGR2", "REGION1", "STRAT1", "STRAT2", "SUBGR1", "SUBGR2", 
                                 "SUBGR3", "SUBGR4", "SUBGR5", "SUBGR6", "SUBGR7", "SUBGR8")),
    selected = NULL
  )
)

Default UI of lineplot_module call:

Custom teal modules


Final teal module render:

User Feedback


We asked our stakeholders to fill out a survey to collect their feedback.


Key Takeaway:
All users found the tool easy to use and reported that it helped them achieve their exploratory analysis goals.

Most Useful Features:

  • “Real-time data updates”
  • “Pattern assessment for ICEs”
  • “Interactive selection and filter”
  • “Interactive visual elements (e.g., displaying LS means when hovering over points in a line plot)”

Q&A